﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Caching;

namespace mytechblog.Managers
{
    public static class DataManager
    {
        private static object cacheLockObject = new object();

        private static T GetFromCache<T>(string cacheKey, Func<T> entityGet) where T: class
        {
            var cache = MemoryCache.Default;
            if (cache[cacheKey] == null)
            {
                lock (cacheLockObject)
                {
                    if (cache[cacheKey] == null)
                    {
                        var entities = entityGet();
                        cache.Set(cacheKey, entities, DateTimeOffset.Now.AddHours(1));
                    }
                }
            }
            return cache[cacheKey] as T;
        }

        public static List<Article> GetArticles()
        {
            const string cacheKey = "cache_articles";
            return GetFromCache<List<Article>>(cacheKey, () => 
            {
                using (var db = new dbEntities())
                {
                    return db.Article.Where(ar => ar.IsVisible).OrderByDescending(ar => ar.DatePosted).ToList();
                }
            });
        }

        public static List<Article> GetArticlesToEdit()
        {
            using (var db = new dbEntities())
            {
                return db.Article.OrderByDescending(ar => ar.DatePosted).ToList();
            }
        }

        public static List<Article> GetArticles(int categoryId)
        {
            string cacheKey = "cache_articles_categoryId_" + categoryId.ToString();
            return GetFromCache<List<Article>>(cacheKey, () =>
            {
                using (var db = new dbEntities())
                {
                    return (from art in db.Article
                            join arToCt in db.ArticleToArticleCategory on art.ID equals arToCt.ArticleID
                            where arToCt.ArticleCategoryID == categoryId && art.IsVisible
                            orderby art.DatePosted descending
                            select art).ToList();
                }
            });
        }

        public static Article GetArticle(int articleId, bool needFresh = false)
        {
            Func<Article> getArticleFunc = () =>
            {
                using (var db = new dbEntities())
                {
                    return db.Article.Where(art => art.ID == articleId).FirstOrDefault();
                }
            };
            if (needFresh)
            {
                return getArticleFunc();
            }
            string cacheKey = "cache_article_" + articleId.ToString();
            return GetFromCache<Article>(cacheKey, getArticleFunc);
        }

        public static long SaveArticle(Article article)
        {
            using (var db = new dbEntities())
            {
                article.DateChanged = DateTime.Now;
                if (article.ID == 0) //add
                {
                    db.Article.AddObject(article);
                    article.DatePosted = DateTime.Now;
                }
                else
                {
                    var oldArticle = db.Article.Where(art => art.ID == article.ID).FirstOrDefault();
                    article.DatePosted = oldArticle.DatePosted;
                    db.Article.ApplyCurrentValues(article);
                }
                db.SaveChanges();
                return article.ID;
            }
        }

        public static List<ArticleCategories> GetCategories()
        {
            const string cacheKey = "cache_categories";
            return GetFromCache<List<ArticleCategories>>(cacheKey, () =>
            {
                using (var db = new dbEntities())
                {
                    return db.ArticleCategories.Where(ac => ac.ArticleToArticleCategory.Count > 0).ToList();
                }
            });
        }

        public static ArticleCategories GetCategory(int categoryId)
        {
            string cacheKey = "cache_category_" + categoryId;
            return GetFromCache<ArticleCategories>(cacheKey, () =>
            {
                using (var db = new dbEntities())
                {
                    return db.ArticleCategories.Where(ct => ct.ID == categoryId).FirstOrDefault();
                }
            });
        }
    }
}